﻿using Abp.Authorization;
using Abp.Domain.Repositories;
using shenghua.Authorization;
using shenghua.Basics.ShippingTemplates;
using shenghua.Commodity.Commodities;
using shenghua.Common.Dto;
using shenghua.Member.Coupons;
using shenghua.Member.ShippingAddresses;
using shenghua.Order.Orders.Dto;
using shenghua.Order.Orders.Median;
using shenghua.Order.Refunds;
using shenghua.Payment.Payments;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using static shenghua.Order.Orders.Dto.OrderShipWuliuDto;

namespace shenghua.Order.Orders
{
    [AbpAuthorize(PermissionNames.Member)]
    public class OrderAppService : shenghuaAppServiceBase, IOrderAppService
    {
        private readonly OrderManager _orderManager;
        private readonly IRepository<Order> _orderRepository;
        private readonly CommodityManager _commodityManager;
        private readonly MemberShippingAddressManager _memberShippingAddressManager;
        private readonly ShippingTemplateManager _shippingTemplateManager;
        private readonly MemberCouponManager _memberCouponManager;
        private readonly RefundManager _refundManager;
        private readonly OrderEvaluateManager _orderEvaluateManager;

        public OrderAppService(
            OrderManager orderManager,
            IRepository<Order> orderRepository,
            CommodityManager commodityManager,
            MemberShippingAddressManager memberShippingAddressManager,
            ShippingTemplateManager shippingTemplateManager,
            MemberCouponManager memberCouponManager,
            RefundManager refundManager,
            OrderEvaluateManager orderEvaluateManager
            )
        {
            _orderManager = orderManager;
            _orderRepository = orderRepository;
            _commodityManager = commodityManager;
            _memberShippingAddressManager = memberShippingAddressManager;
            _shippingTemplateManager = shippingTemplateManager;
            _memberCouponManager = memberCouponManager;
            _refundManager = refundManager;
            _orderEvaluateManager = orderEvaluateManager;
        }

        /// <summary>
        /// 生成订单
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task<OrderDto> GenerateOrder(GenerateOrderDto input)
        {
            var member = await GetCurrentMemberAsync();
            var orderCore = await GetOrderCore(member, input);
            Order order = await _orderManager.CreateOrder(orderCore, input.Remark, input.IsFromShoppingCart);
            var details = await _orderManager.GetDetails(order.Id);
            return new OrderDto(order, details);
        }

        /// <summary>
        /// 计算订单数据
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task<OrderCoreDto> CalculateOrderData(GenerateOrderDto input)
        {
            var member = await GetCurrentMemberAsync();
            var orderCore = await GetOrderCore(member, input);
            var canUsedCoupons = await _memberCouponManager.GetCanUsedCoupons(member.Id, orderCore.CommodityCollection.Items);
            List<ShippingTemplate> canUsedShippingTemplates = null;
            if (orderCore.DeliveryAddress != null) {
                canUsedShippingTemplates = await _shippingTemplateManager.GetCanUsed(orderCore.DeliveryAddress.AreaTag);
            }
            return new OrderCoreDto(orderCore, canUsedCoupons, canUsedShippingTemplates);
        }

        /// <summary>
        /// 得到订单核
        /// </summary>
        /// <param name="member"></param>
        /// <param name="input"></param>
        /// <returns></returns>
        private async Task<OrderCore> GetOrderCore(Member.Members.Member member, GenerateOrderDto input)
        {
            List<CommodityCollectionItem> commodityCollectionItems = new List<CommodityCollectionItem>();
            foreach(var item in input.Items)
            {
                var commodityCollectionItem = await _commodityManager.GetCommodityCollectionItem(member, item.Count, item.CommodityId, item.ShoppingOptionId);
                commodityCollectionItems.Add(commodityCollectionItem);
            }

            MemberShippingAddress deliveryAddress = null;
            if (input.DeliveryAddressId != null)
            {
                deliveryAddress = await _memberShippingAddressManager.Get(member.Id, (int)input.DeliveryAddressId);
            }

            ShippingTemplate shippingTemplate = null;
            if (input.ShippingTemplateId != null)
            {
                shippingTemplate = shippingTemplate = await _shippingTemplateManager.Get((int)input.ShippingTemplateId);
            }

            MemberCoupon coupon = null;
            if (input.CouponId != null)
            {
                coupon = await _memberCouponManager.Get(member.Id, (int)input.CouponId);
            }

            var orderCore = await _orderManager.GetOrderCore(
                member, commodityCollectionItems, deliveryAddress, shippingTemplate, input.PaymentType, coupon, input.UsedXPValue);

            return orderCore;
        }

        public async Task<OrderDto> Get(OrderNumberDto input)
        {
            var item = await _orderManager.Get(MemberId, input.OrderNumber);
            var details = await _orderManager.GetDetails(item.Id);
            return new OrderDto(item, details);
        }

        public async Task<SearchResultDto<OrderDto>> Search(SearchOrderDto input)
        {
            var query = _orderRepository.GetAll().Where(r => r.MemberInfo.Id == MemberId);

            if (!string.IsNullOrWhiteSpace(input.Search))
            {
                switch (input.SearchTarget)
                {
                    case "orderNumber": query = query.Where(r => r.OrderNumber == input.Search); break;
                    case "userName": query = query.Where(r => r.MemberInfo.UserName == input.Search); break;
                    case "phoneNumber": query = query.Where(r => r.ShipInfo.PhoneNumber == input.Search); break;
                    case "subject": query = query.Where(r => r.Info.Subject.Contains(input.Search)); break;
                }
            }

            if (input.Begin != null)
            {
                query = query.Where(r => r.Info.CreationTime >= input.Begin);
            }

            if (input.End != null)
            {
                query = query.Where(r => r.Info.CreationTime <= input.End);
            }

            if (!string.IsNullOrWhiteSpace(input.Status))
            {
                switch (input.Status)
                {
                    case "all": break;
                    case "pendingPay": query = query.Where(r => r.Info.Status == Median.OrderStatus.Created && r.PaymentInfo.PaymentStatus == OrderPaymentStatus.PendingPay); break;
                    case "pendingShip": query = query.Where(r => r.Info.Status == Median.OrderStatus.Created && r.ShipInfo.ShipStatus == OrderShipStatus.PendingShip); break;
                    case "shipped": query = query.Where(r => r.Info.Status == Median.OrderStatus.Created && r.ShipInfo.ShipStatus == OrderShipStatus.Shipped); break;
                    case "pendingFinish": query = query.Where(r => r.Info.Status == Median.OrderStatus.Created && r.ShipInfo.ShipStatus == OrderShipStatus.Received && r.PaymentInfo.PaymentStatus == OrderPaymentStatus.Paid); break;
                    case "finished": query = query.Where(r => r.Info.Status == Median.OrderStatus.Succeeded); break;
                    case "closed": query = query.Where(r => r.Info.Status == Median.OrderStatus.Closed); break;
                }
            }

            var totalCount = query.Count();
            var items = query.OrderByDescending(r => r.Info.CreationTime).Skip(input.SkipCount).Take(input.MaxResultCount).ToList();

            List<OrderDto> orderDtos = new List<OrderDto>();
            foreach (var item in items)
            {
                var details = await _orderManager.GetDetails(item.Id);
                orderDtos.Add(new OrderDto(item, details));
            }

            return new SearchResultDto<OrderDto>
            {
                TotalCount = totalCount,
                Items = orderDtos
            };
        }

        /// <summary>
        /// 获取支付页面
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task<string> GeneratePaymentPage(GeneratePaymentPageDto input)
        {
            return await _orderManager.GeneratePaymentPage(input.OrderNumber, input.PaymentMethod);
        }

        public async Task CancelOrder(OrderNumberDto input)
        {
            await _orderManager.CancelOrder(MemberId, input.OrderNumber);
        }

        public async Task DeleteOrder(OrderNumberDto input)
        {
            await _orderManager.DeleteOrder(MemberId, input.OrderNumber);
        }

        public async Task ConfirmReceipt(OrderNumberDto input)
        {
            await _orderManager.ConfirmReceipt(MemberId, input.OrderNumber);
        }

        public async Task FinishOrder(OrderNumberDto input)
        {
            await _orderManager.FinishedOrder(MemberId, input.OrderNumber);
        }

        /// <summary>
        /// 获取物流信息
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task<OrderShipWuliuDto> GetOrderWuliu(OrderNumberDto input)
        {
            try
            {
                var orderShipWuliu = await _orderManager.GetOrderWuliu(MemberId, input.OrderNumber);
                return ObjectMapper.Map<OrderShipWuliuDto>(orderShipWuliu);
            }
            catch (Exception e)
            {
                var result = new OrderShipWuliuDto();
                result.Errors.Add(e.Message);
                return result;
            }
        }

        /// <summary>
        /// 得到订单的所有日志
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task<List<OrderLogDto>> GetAllOrderLogs(OrderNumberDto input)
        {
            var items = await _orderManager.GetAllOrderLogs(MemberId, input.OrderNumber);
            return ObjectMapper.Map<List<OrderLogDto>>(items);
        }

        public async Task<List<RefundDto>> GetOrderRefunds(OrderNumberDto input)
        {
            var items = await _refundManager.GetAllOfOrder(MemberId, input.OrderNumber);
            return ObjectMapper.Map<List<RefundDto>>(items);
        }

        public async Task<List<RefundDto>> GetAllRefunds()
        {
            var items = await _refundManager.GetAll(MemberId);
            return ObjectMapper.Map<List<RefundDto>>(items);
        }

        /// <summary>
        /// 对订单进行评论。之后的追加评论，管理员评论，其他会员的评论，这些都不在此范畴，是另外的模块进行处理
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task EvaluateOrder(EvaluateOrderDto input)
        {
            var member = await GetCurrentMemberAsync();
            await _orderManager.EvaluateOrder(member, input.OrderNumber, input.RateValue, input.Content, input.Pictures);
        }
        
        public async Task<List<OrderEvaluateDto>> GetOrderEvaluates(OrderNumberDto input)
        {
            var items = await _orderEvaluateManager.GetOrderComments(MemberId, input.OrderNumber);
            return items.Select(r => new OrderEvaluateDto(r)).ToList();
        }
    }
}
